const nsISupports = Components.interfaces.nsISupports;
const CTParseServiceInt = Components.interfaces.CTParseServiceInt;

// You can change these if you like
const CLASS_ID = Components.ID("a5798406-e77b-4e72-b540-3163ea6bb47f");
const CLASS_NAME = "crunch time file parsing service";
const CONTRACT_ID = "@crunch.time/ctparseservice;1";

function CTParseService() {
    this.wrappedJSObject = this;
	
    this.tasks = [];
    this.sites =[];
	this.scheduled = [];
	
}

//implementation!
CTParseService.prototype = {
	
getTaskList: function(){
	var jsArray = [];
	this.tasks = jsArray;
	
	// open an input stream from file given by the preferences object.
	var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.crunchtime.");	    
	var basePath = prefs.getCharPref("basepath");
	var eventPath = basePath+"/eventlist.txt";
	var file = prefs.getComplexValue("eventpath", Components.interfaces.nsILocalFile);
	var istream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);  
	istream.init(file, 0x01, 0444, 0);  
	istream.QueryInterface(Components.interfaces.nsILineInputStream);  
	
	var line = {}, lines = [], hasmore;  
	do {  
		hasmore = istream.readLine(line);  
		lines.push(line.value);   
	} while(hasmore);  
	istream.close();
	
	
	
	for(var i=0; i<lines.length; i++)
	{
		dump("line: " + lines[i] + "\n");
		var chunks = lines[i].split("*");
		if(chunks.length ==2)
		{
		    dump("Name chunk: " + chunks[0] + "\n");
		    dump("Date chunk: " + chunks[1] + "\n");
		    this.tasks.push(chunks); 
		}
	}
	
	return this.tasks;
},
getScheduledList: function(){
	var jsArray = [];
	this.scheduled = jsArray;
	
	// open an input stream from file given by the preferences object.
	var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.crunchtime.");	    
	var basePath = prefs.getCharPref("basepath");
	var scheduledPath = basePath+"/scheduledlist.txt";
	var file = prefs.getComplexValue("scheduledpath", Components.interfaces.nsILocalFile);
	var istream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);  
	istream.init(file, 0x01, 0444, 0);  
	istream.QueryInterface(Components.interfaces.nsILineInputStream);  
	
	var line = {}, lines = [], hasmore;  
	do {  
		hasmore = istream.readLine(line);  
		lines.push(line.value);   
	} while(hasmore);  
	istream.close();
	
	for(var i=0; i<lines.length; i++)
	{
		dump("line: " + lines[i] + "\n");
		var chunks = lines[i].split("*");
		if(chunks.length ==2)
		{
		    dump("Name chunk: " + chunks[0] + "\n");
		    dump("Date chunk: " + chunks[1] + "\n");
		    this.scheduled.push(chunks); 
		}
	}
	
	return this.scheduled;
},
	
    //same comments as above, but the array returned is an array of strings.
getSiteList: function(){
	var jsArray = [];
	this.sites = jsArray;
	var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.crunchtime.");
	var file = prefs.getComplexValue("sitepath", Components.interfaces.nsILocalFile);
	
	// open an input stream from file  
	var istream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);  
	istream.init(file, 0x01, 0444, 0);  
	istream.QueryInterface(Components.interfaces.nsILineInputStream);  
	
	// read lines into array  
	var line = {}, lines = [], hasmore;  
	do {  
		hasmore = istream.readLine(line);  
		lines.push(line.value);   
	} while(hasmore);  
	
	istream.close();  
	
	for(var i=0; i<lines.length; i++)
	{
		if(lines[i]!="")
			this.sites.push(lines[i]);
	}
	for(var index =0; index < this.tasks.length; index++)
	{
		dump("Task "+ this.sites[index]+"\n");
	}
	return this.sites;
},
	
addTask: function(name, date){
	dump("CTPS name: " + name + "\n");
	dump("CTPS date: " + date + "\n");
	dump("tasks.length: " + this.tasks.length +"\n");
	
	if(this.tasks.length == 0){
	    this.tasks = this.getTaskList();
	}
	
	var task = [name, date];
	this.tasks.push(task);
	
	for(var index =0; index < this.tasks.length; index++)
	{
		dump("Task"+ this.tasks[index][0]+ ", "+ this.tasks[index][1]+"\n");
	}
	this.writeTaskList(); //write to the file after you add the task.
	this.tasks = this.getTaskList();
},
    
removeTask: function(name){
	dump("HJALSKFJLAKE");
	if(this.tasks.length == 0){ //sanity check.
	    this.tasks = this.getTaskList();   
	}
	
	for(var i=0; i < this.tasks.length;i++){
	    if(this.tasks[i][0] == name){
			this.tasks.splice(i,1); //remove the element from the array of tasks
			dump(this.tasks);
			this.writeTaskList();   //write to the file after you remove the task.
			return true;
	    }
	}
	
	this.tasks = this.getTaskList();
	for(var j=0; j < this.tasks.length; j++){
	    if(this.tasks[j][1] == name){
			dump("YES");
			this.tasks.splice(j,1); //remove the element from the array of tasks
			dump(this.tasks);
			this.writeTaskList();   //write to the file after you remove the task.
			return true;
	    }
	}
	
	return false; //the task that you wanted to remove didn't exist. 
},
	
addScheduled: function(name, date){
	dump("CTPS name: " + name + "\n");
	dump("CTPS date: " + date + "\n");
	dump("tasks.length: " + this.scheduled.length +"\n");
	
	if(this.scheduled.length == 0){
	    this.scheduled = this.getScheduledList();
	}
	
	var task = [name, date];
	this.scheduled.push(task);
	
	for(var index =0; index < this.scheduled.length; index++)
	{
		dump("scheduled: "+ this.scheduled[index][0]+ ", "+ this.scheduled[index][1]+"\n");
	}
	this.writeScheduledList(); //write to the file after you add the task.
	this.scheduled = this.getScheduledList();
},
removeScheduled: function(blockTime){
	
	if(this.scheduled.length == 0){ //sanity check.
	    this.scheduled = this.getScheduledList();   
	}
	
	for(var i=0; i < this.scheduled.length; i++){
		var id = this.scheduled[i][0]+"*"+this.scheduled[i][1];
		dump("\n"+ id+" "+blockTime);
	    if(id == blockTime){
			this.scheduled.splice(i,1); //remove the element from the array of tasks
			dump(this.scheduled);
			this.writeScheduledList();   //write to the file after you remove the task.
			return true;
	    }
	}
	return false; //the task that you wanted to remove didn't exist. 
},
	
addScheduledToTasks: function(p1, p2){
	this.tasks = this.getTaskList();   
	this.scheduled = this.getScheduledList();  
	
	for(var i =0 ; i <this.scheduled.length; i++)
	{
		var givenDate = new Date(this.scheduled[i][1]);
		var currentDate = new Date();
		currentDate.setMinutes(givenDate.getMinutes());
		currentDate.setSeconds(givenDate.getSeconds());
		currentDate.setHours(givenDate.getHours());
		
		var monthname=new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
		var hour = currentDate.getHours();
		if (hour <10)
			hour = "0"+currentDate.getHours();
		var minute = currentDate.getMinutes();
		if (minute <10)
			minute = "0"+currentDate.getMinutes();
		var day = currentDate.getDate();
		if (day <10)
			day = "0"+currentDate.getDate();
		var dateString = monthname[currentDate.getMonth()] +" "+ day+", " + currentDate.getFullYear() +" "+hour+":"+minute+":00";
		
		
		this.addTask("Daily Scheduled Blocking", dateString);
	}
},
    
addSite: function(siteName){
	if(this.sites.length == 0){
		this.sites = this.getSiteList();
	}
	//make sure it's not already there by removing it first. 
	//either way, we have to push it on the end of the array.
	this.removeSite(siteName);
	this.sites.push(siteName);
	for(var i = 0; i < this.sites.length; i++){
		dump(this.sites[i]+", ");
	}
	this.writeSiteList();
	this.sites = this.getSiteList();
},
    
    //this is pretty much the same function as removeTask(taskName); 
removeSite: function(siteName){
	if(this.sites.length == 0){
	    this.sites = this.getSiteList();
	}
	
	for(i = 0; i < this.sites.length;i++){
	    if(this.sites[i] == siteName){
			this.sites.splice(i,1);
			this.writeSiteList();
			return true;
	    }	    
	}
	return false; //the site wasn't there, so we removed nothing.
},
	
shouldBlock: function(url){
	this.tasks = this.getTaskList();
	this.sites = this.getSiteList();
	dump(this.tasks);
	dump(this.sites);
	
	var millisecsInHour = 3600000;
	
	//get the preference for how many hours before you want to block.
	//...
	var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.crunchtime.");
	var timeBefore = prefs.getIntPref("blockbefore") * millisecsInHour;
	var timeAfter = prefs.getIntPref("blockafter") * millisecsInHour;
	
	var curDate = new Date();
	//check sites;
	for(var i = 0; i < this.sites.length; i++)
	{   
	    if(this.sites[i] == url)
		{
			//check tasks
			for(var j = 0; j < this.tasks.length; j++)
			{		    
				var taskDate = new Date(this.tasks[j][1]);
				var timeDiff = taskDate - curDate;
				if(timeDiff < 0 && Math.abs(timeDiff) < timeAfter)
				{
					dump("is blocking");
					return true;
				}
				if(timeDiff >= 0 && timeDiff < timeBefore)
				{
					dump("is blocking");
					return true;
				}
			}
	    }
	}
	return false;
},
    
	
writeTaskList: function(){
	//build up the list of tasks
	var data = "";
	dump("---------------\n");
	
	for(var index =0; index < this.tasks.length; index++)
	{
		var string = this.tasks[index][0] + "*" + this.tasks[index][1] + "\n";
		data = data + string;
		dump(string);	    
	}
	
	var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.crunchtime.");
	
	var file = prefs.getComplexValue("eventpath", Components.interfaces.nsILocalFile);
	var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);  
	foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0);   //initialize the file (basically opens it).
	foStream.write(data, data.length);
	foStream.close(); //clean up, clean up, everybody everywhere!
},
	
writeScheduledList: function(){
	//build up the list of tasks
	var data = "";
	dump("---------------\n");
	
	for(var index =0; index < this.scheduled.length; index++)
	{
		var string = this.scheduled[index][0] + "*" + this.scheduled[index][1] + "\n";
		data = data + string;
		dump(string);	    
	}
	
	var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.crunchtime.");
	
	var file = prefs.getComplexValue("scheduledpath", Components.interfaces.nsILocalFile);
	var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);  
	foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0);   //initialize the file (basically opens it).
	foStream.write(data, data.length);
	foStream.close(); //clean up, clean up, everybody everywhere!
},
    
writeSiteList: function(){
	//build up string to write to file
	var data = "";
	dump("---------------\n");
	for(var index =0; index < this.sites.length; index++)
	{
		var string = this.sites[index] + "\n";
		data = data + string;
		dump(string);
	}
	
	
	var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.crunchtime.");
	var file = prefs.getComplexValue("sitepath", Components.interfaces.nsILocalFile); //get the file
	var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);  
	foStream.init(file, 0x02 | 0x08 | 0x20, 0666, 0);   //initialize the file (basically opens it).
	foStream.write(data, data.length);
	foStream.close(); //clean up, clean up, everybody everywhere!
},
    
wouldBlock: function(){
	if(this.tasks.length == 0){
	    this.tasks = this.getTaskList();	    
	}
	
	var millisecsInHour = 3600000;
	var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.crunchtime.");
	var timeBefore = prefs.getIntPref("blockbefore") * millisecsInHour;
	var timeAfter = prefs.getIntPref("blockafter") * millisecsInHour;	
	var curDate = new Date();
	
	for(var j = 0; j < this.tasks.length; j++){		    
	    var taskDate = new Date(this.tasks[j][1]);
	    var timeDiff = taskDate - curDate;
	    if(timeDiff < 0 && Math.abs(timeDiff) < timeAfter){
			return true;
	    }
	    if(timeDiff >= 0 && timeDiff < timeBefore){
			return true;
	    }
	}
	
	return false;	
},
    
blockingTask: function(){
	if(this.tasks.length == 0){
	    this.tasks = getTaskList();	    
	}
	
	var millisecsInHour = 3600000;
	var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.crunchtime.");
	var timeBefore = prefs.getIntPref("blockbefore") * millisecsInHour;
	var timeAfter = prefs.getIntPref("blockafter") * millisecsInHour;	
	var curDate = new Date();
	
	for(var i = 0; i < this.tasks.length; i++){
	    var taskDate = new Date(this.tasks[i][1]);
	    var timeDiff = taskDate - curDate;
	    if(timeDiff < 0 && Math.abs(timeDiff) < timeAfter){
			if(this.tasks[i][0] == "")                              //support for a task with no name.
				return "You are being blocked for a task with no name.";
			return this.tasks[i][0]; //return the name of the task
	    }
	    if(timeDiff >= 0 && timeDiff < timeBefore){
			if(this.tasks[i][0] == "")
				return "You are being blocked for a task with no name.";
			return this.tasks[i][0]; //return the name of the task
	    }
	}
	return "";	//no task. sad day. return empty string.
},
	
removeAllBlockingTasks: function(){
	if(this.tasks.length == 0){
	    this.tasks = getTaskList();	    
	}
	
	var millisecsInHour = 3600000;
	var prefs = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefService).getBranch("extensions.crunchtime.");
	var timeBefore = prefs.getIntPref("blockbefore") * millisecsInHour;
	var timeAfter = prefs.getIntPref("blockafter") * millisecsInHour;	
	var curDate = new Date();
	
	while(this.wouldBlock()){
	    for(var i = 0; i < this.tasks.length; i++){
			var taskDate = new Date(this.tasks[i][1]);
			dump("inblock"+ taskDate+"\n");
			var timeDiff = taskDate - curDate;
			dump("timeDiff" + timeDiff+"\n");
			if(timeDiff < 0 && Math.abs(timeDiff) < timeAfter){
				this.tasks.splice(i,1); //remove the element from the array of tasks
				this.writeTaskList();
				break;		    
			}
			if(timeDiff >= 0 && timeDiff < timeBefore){
				this.tasks.splice(i,1); //remove the element from the array of tasks
				this.writeTaskList();
				break;
			}
	    }
	}
	this.writeTaskList();   //write to the file after you remove the task.
	this.tasks = this.getTaskList();
	this.sites = this.getSiteList();
},
	
    // for nsISupports
QueryInterface: function(aIID)
    {
		// add any other interfaces you support here
		if (!aIID.equals(nsISupports) && !aIID.equals(CTParseServiceInt))
			throw Components.results.NS_ERROR_NO_INTERFACE;
		return this;
    }
};

//=================================================
// Note: You probably don't want to edit anything
// below this unless you know what you're doing.
//
// Factory
//    var CTParseServiceFactory = {
//	singleton: null,
//	createInstance: function (aOuter, aIID)
//	{
//	    if (aOuter != null)
//		throw Components.results.NS_ERROR_NO_AGGREGATION;
//	    if (this.singleton == null)
//		this.singleton = new CTParseService();
//	    return this.singleton.QueryInterface(aIID);
//	}
//  };

// Factory
var CTParseServiceFactory = {
createInstance: function (aOuter, aIID)
    {
		if (aOuter != null)
			throw Components.results.NS_ERROR_NO_AGGREGATION;
		return (new CTParseService()).QueryInterface(aIID);
    }
};

// Module
var CTParseServiceModule = {
registerSelf: function(aCompMgr, aFileSpec, aLocation, aType)
    {
		aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
		aCompMgr.registerFactoryLocation(CLASS_ID, CLASS_NAME, CONTRACT_ID, aFileSpec, aLocation, aType);
    },
	
unregisterSelf: function(aCompMgr, aLocation, aType)
    {
		aCompMgr = aCompMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
		aCompMgr.unregisterFactoryLocation(CLASS_ID, aLocation);        
    },
    
getClassObject: function(aCompMgr, aCID, aIID)
    {
		if (!aIID.equals(Components.interfaces.nsIFactory))
			throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
		
		if (aCID.equals(CLASS_ID))
			return CTParseServiceFactory;
		
		throw Components.results.NS_ERROR_NO_INTERFACE;
    },
	
canUnload: function(aCompMgr) { return true; }
};

//module initialization
function NSGetModule(aCompMgr, aFileSpec) { return CTParseServiceModule; }
